﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.WindowsPresentation;
using Kinect.Toolbox;
using Kinect.Toolbox.Analyzers;
using Kinect.Toolbox.Collectors;
using Kinect.Toolbox.Extensions;
using Microsoft.Kinect;
using Microsoft.Practices.Unity;
using Model;

namespace Gui.ViewModels
{
    public class MapViewModel : INotifyPropertyChanged
    {
        private PostureAnalyzer _postureAnalyzer;
        private MovementAnalyzer _leftHandMovementAnalyzer;
        private ContinousMovementAnalyzer _headMovementAnalyzer;
        private ParallelSwipeAnalyzer _parallelSwipeAnalyzer;

        private int _zoom;
        private readonly IViewConfiguration _viewConfiguration;
        private readonly IMapDefinition _mapDefinition;

        public PointLatLng Position
        {
            get { return _mapDefinition.Position; }
            private set
            {
                _mapDefinition.Position = value;

                OnPropertyChanged("Position");
            }
        }

        public int Zoom
        {
            get { return _zoom; }
            private set
            {
                _zoom = value;
                OnPropertyChanged("Zoom");
            }
        }

        public bool IsHandNavigationMode
        {
            get { return _viewConfiguration.IsHandNavigationMode; }
        }

        public bool IsHeadNavigationMode
        {
            get { return _viewConfiguration.IsHeadNavigationMode; }
        }

        public ObservableCollection<GMapMarker> Markers { get; private set; }

        public MapViewModel()
        {
            _viewConfiguration = DependencyFactory.Container.Resolve<IViewConfiguration>();
            _mapDefinition = DependencyFactory.Container.Resolve<IMapDefinition>();
            Markers = _mapDefinition.Markers;

            InitializeMap();
            RegisterOnKinectEvents();
        }

        private void RegisterOnKinectEvents()
        {
            var kinectSensor = DependencyFactory.Container.Resolve<KinectSensor>();
            var framesCollector = new FramesCollector(kinectSensor);

            _postureAnalyzer = new PostureAnalyzer(framesCollector);
            _postureAnalyzer.PostureDetected += PostureAnalyzerOnPostureDetected;

            var stabilityFramesCollector = new FramesCollector(kinectSensor, 40);
            var skeletonStabilityAnalyzeExtension = new SkeletonStabilityAnalyzeExtension(stabilityFramesCollector);

            var shortFramesCollector = new FramesCollector(kinectSensor, 5);
            _leftHandMovementAnalyzer = new MovementAnalyzer(shortFramesCollector, JointType.HandLeft);
            _leftHandMovementAnalyzer.AddBeforeAnalyzeExtension(skeletonStabilityAnalyzeExtension);
            _leftHandMovementAnalyzer.MovementDetected += MovementAnalyzerOnOnMovementGestureDetected;

            _headMovementAnalyzer = new ContinousMovementAnalyzer(shortFramesCollector, JointType.Head) { MinimalVectorLength = 0.001f };
            _headMovementAnalyzer.AddBeforeAnalyzeExtension(skeletonStabilityAnalyzeExtension);
            _headMovementAnalyzer.MovementDetected += MovementAnalyzerOnOnMovementGestureDetected;

            _parallelSwipeAnalyzer = new ParallelSwipeAnalyzer(framesCollector);
            _parallelSwipeAnalyzer.ParallelSwipeDetected += ParallelSwipeAnalyzerOnParallelSwipeDetected;
        }

        private void ParallelSwipeAnalyzerOnParallelSwipeDetected(object sender, SwipeEventArgs args)
        {
            if (args.Gesture == GesturesEnum.SwipeOut)
            {
                Zoom++;
            }
            if (args.Gesture == GesturesEnum.SwipeIn)
            {
                Zoom--;
            }
        }

        private void InitializeMap()
        {
            Position = Utils.GetPositionByKeywords("Kraków");
            Zoom = 9;
        }

        private void PostureAnalyzerOnPostureDetected(object sender, PostureEventArgs args)
        {
            switch (args.Posture)
            {
                case PosturesEnum.RightHello:
                    {
                        _mapDefinition.Markers.Add(new GMapMarker(new PointLatLng())
                        {
                            Position = new PointLatLng(Position.Lat, Position.Lng),
                            ZIndex = int.MaxValue,
                            Shape =
                                new Label
                                {
                                    Width = 50,
                                    Content = "Flaga",
                                    Background = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0))
                                }
                        });
                    }
                    break;
                case PosturesEnum.HandsJoined:
                    {
                        if (_mapDefinition.Markers.Count == 0)
                        {
                            return;
                        }
                        var mRoute = new GMapMarker(_mapDefinition.Markers[0].Position);
                        {
                            mRoute.Route.AddRange(_mapDefinition.Markers.Select(a => a.Position));
                            var gMapControl = _mapDefinition.Markers[0].Map;
                            mRoute.RegenerateRouteShape(gMapControl);
                            mRoute.ZIndex = -1;
                        }
                        _mapDefinition.Markers.Add(mRoute);
                    }
                    break;
            }
        }

        private void MovementAnalyzerOnOnMovementGestureDetected(object sender, MovementEventArgs movementEventArgs)
        {
            if (IsHeadNavigationMode && movementEventArgs.JointType == JointType.Head)
            {
                const int amplification = 50;
                Position = new PointLatLng(Position.Lat + movementEventArgs.Displacement.Y * amplification, Position.Lng + movementEventArgs.Displacement.X * amplification);
            }
            if (IsHandNavigationMode && movementEventArgs.JointType == JointType.HandLeft)
            {
                //czas wykonania - wzmacnia efekt
                var amplification = movementEventArgs.Duration / 200;
                //przesuniecie jak w smartfonach - w odwrotnym kierunku
                Position = new PointLatLng(Position.Lat - movementEventArgs.Displacement.Y * amplification, Position.Lng - movementEventArgs.Displacement.X * amplification);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}
